import { Option, ParseOption } from "../opt/Option";
import { Choice, M698pdu } from "../axdr/M698pdu";
import {
    GetRequestOption,
} from "../opt/GetRequestOption";
import { DataUtils } from "../DataUtils";
import { Apdu } from "../axdr/Apdu";
import { HdlcFrame } from "../sessionlayer.hdlc/HdlcFrame";

import { ConnectRequestOption } from "../opt/ConnectRequestOption";
import { SecurityRequestOption } from "../opt/SecurityRequestOption";

import { ReverseByteArrayInputStream } from "../ReverseByteArrayInputStream";
import { ReverseByteArrayOutputStream } from "../ReverseByteArrayOutputStream";
import { resultCode } from "../tools/DataTool";
import {
    parseGetResponseNext,
    parseGetResponseNormal,
    parseGetResponseNormalList,
    parseGetResponseRecord,
    parseGetResponseRecordList
} from "../parse/ParseGetResponse";
import { parseSetNormalResponse, parseSetNormalResponseList, parseSetThenGetResponse } from "../parse/ParseSetResponse";

import { parseConnectResponse, parseSecurityResponse } from "../parse/ParseAuthResponse";
import { FrameData } from "../bean/FrameData";
import { buildGetRequest } from "../build/BuildGetRequest";
import { buildSetRequest } from "../build/BuildSetRequest";
import { buildActionRequest } from "../build/BuildActionRequest";
import { buildConnectRequest } from "../build/BuildConnectRequest";
import { buildProxyRequest } from "../build/BuildProxyRequest";
import { buildSecurityRequest } from "../build/BuildSecurityRequest";
import { SetRequestOption } from "../opt/SetRequestOption";
import { ActionRequestOption } from "../opt/ActionRequestOption";
import { ProxyRequestOption } from "../opt/ProxyRequestOption";
import { parseActionResponseNormal, parseActionResponseNormalList, parseActionThenGetResponseList } from "../parse/ParseActionResponse";
import { parseProxyActionResponseList, parseProxyActionThenGetResponseList, parseProxyGetRecord, parseProxyGetResponseList, parseProxySetResponseNormalList, parseProxySetThenGetResponseList, parseProxyTransCommand } from "../parse/ParseProxyResponse";


export class TS698 {

    private static instance: TS698 = null;

    private constructor() {

    }


    public static getInstance(): TS698 {
        if (!this.instance) {
            this.instance = new TS698();
        }
        return this.instance;
    }


    buildFrame(param: Option) {
        let data: String = "";
        let link_opt = param.link_option;
        let request_option = param.request_option;

        // 请求配置不能为空
        if (link_opt == null || request_option == null) {
            data = "link_option or request_option not allow empty";
            param.error({
                resultCode: resultCode.emptyError,
                msg: data
            })
            return;
        }
        // 链路层配置所需参数校验
        if (link_opt.server_address == null || link_opt.client_address == null) {
            data = "server_address or client_address not allow empty";
            param.error({
                resultCode: resultCode.emptyError,
                msg: data
            })
            return;
        } else {
            if (link_opt.server_address.length == 0 || link_opt.server_address.length != 12) {
                data = "server_address length is Illegal";
                param.error({
                    resultCode: resultCode.illegalError,
                    msg: data
                })
                return;
            }
            if (link_opt.client_address.length == 0 || link_opt.client_address.length != 2) {
                data = "client_address length is Illegal";
                param.error({
                    resultCode: resultCode.illegalError,
                    msg: data
                })
                return;
            }
        }

        // apdu请求相关配置
        if (request_option.request_mode != Choice.GET_REQUEST
            && request_option.request_mode != Choice.SET_REQUEST
            && request_option.request_mode != Choice.ACTION_REQUEST
            && request_option.request_mode != Choice.CONNECT_REQUEST
            && request_option.request_mode != Choice.PROXY_REQUEST
            && request_option.request_mode != Choice.SECURITY_REQUEST) {
            data = "request_mode length is Illegal";
            param.error({
                resultCode: resultCode.illegalError,
                msg: data
            })
            return;
        } else {
            if (request_option.request_mode == Choice.GET_REQUEST) {
                // get 请求
                let get_opt = request_option.request as GetRequestOption;
                if (get_opt == null || get_opt.get_option == null) {
                    data = "get request not allow empty";
                    param.error({
                        resultCode: resultCode.emptyError,
                        msg: data
                    })
                    return;
                } else {
                    let result = buildGetRequest(get_opt, link_opt, request_option);
                    if (result[0] == resultCode.success) {
                        param.success({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    } else {
                        param.error({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    }
                }
            } else if (request_option.request_mode == Choice.SET_REQUEST) {
                let set_opt = request_option.request as SetRequestOption;
                if (set_opt == null || set_opt.set_option == null) {
                    data = "set request not allow empty";
                    param.error({
                        resultCode: resultCode.emptyError,
                        msg: data
                    })
                    return;
                } else {
                    let result = buildSetRequest(set_opt, link_opt, request_option);
                    if (result[0] == resultCode.success) {
                        param.success({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    } else {
                        param.error({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    }
                }
            } else if (request_option.request_mode == Choice.ACTION_REQUEST) {
                let action_opt = request_option.request as ActionRequestOption;
                if (action_opt == null || action_opt.action_option == null) {
                    data = "action request not allow empty";
                    param.error({
                        resultCode: resultCode.emptyError,
                        msg: data
                    })
                    return;
                } else {
                    let result = buildActionRequest(action_opt, link_opt, request_option);
                    if (result[0] == resultCode.success) {
                        param.success({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    } else {
                        param.error({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    }
                }
            } else if (request_option.request_mode == Choice.CONNECT_REQUEST) {
                let connect_opt = request_option.request as ConnectRequestOption;
                if (connect_opt == null) {
                    data = "connect request not allow empty";
                    param.error({
                        resultCode: resultCode.emptyError,
                        msg: data
                    })
                    return;
                } else {
                    let result = buildConnectRequest(connect_opt, link_opt, request_option);
                    if (result[0] == resultCode.success) {
                        param.success({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    } else {
                        param.error({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    }
                }
            } else if (request_option.request_mode == Choice.PROXY_REQUEST) {
                let proxy_opt = request_option.request as ProxyRequestOption;
                if (proxy_opt == null || proxy_opt.proxy_option == null) {
                    data = "proxy request not allow empty";
                    param.error({
                        resultCode: resultCode.emptyError,
                        msg: data
                    })
                    return;
                } else {
                    let result = buildProxyRequest(proxy_opt, link_opt, request_option);
                    if (result[0] == resultCode.success) {
                        param.success({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    } else {
                        param.error({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    }
                }
            } else if (request_option.request_mode == Choice.SECURITY_REQUEST) {
                let security_opt = request_option.request as SecurityRequestOption;
                if (security_opt == null) {
                    data = "connect request not allow empty";
                    param.error({
                        resultCode: resultCode.emptyError,
                        msg: data
                    })
                    return;
                } else {
                    let result = buildSecurityRequest(security_opt, link_opt, request_option);
                    if (result[0] == resultCode.success) {
                        param.success({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    } else {
                        param.error({
                            resultCode: result[0],
                            msg: result[1]
                        })
                    }
                }
            }
        }

    }

    parseLinkFrame(frame: String): String {
        let frameData = new FrameData();
        let lenPractical = frame.length - 4;//实际长度
        let len_first = frame.substring(2, 4);//帧中的数据长度前两位
        let len_second = frame.substring(4, 6);//帧中数据帧长度后两位
        let len = parseInt(len_second + len_first, 16);
        if (len * 2 != lenPractical) {
            frameData.code = resultCode.illegalError;
            frameData.data = "frame length is illegal";
            return JSON.stringify(frameData);
        }
        // 提取链路层数据帧，获取应用层数据帧
        let appFrame;
        console.log(frame);
        let dataInputStream = new ReverseByteArrayInputStream(DataUtils.hexToBytes(frame.toString()));
        let hdlcFrame;
        try {
            hdlcFrame = new HdlcFrame().decode(dataInputStream);
            if (hdlcFrame.isSegmented()) {
                let s = (hdlcFrame.getSegFrameType() | hdlcFrame.getSegFrameXh()).toString(16);
                while (s.length < 4) {
                    s.slice(0, 1) + "0" + s.slice(1);
                }
                appFrame = s;
            } else {
                let field = hdlcFrame.getInformationField();
                appFrame = DataUtils.toHexString(field, 1, 0);
                console.log(appFrame);
            }
        } catch (e) {
            frameData.code = resultCode.illegalError;
            frameData.data = "frame parse failed";
            return JSON.stringify(frameData);
        }
        return this.parseAppFrame(appFrame);
    }

    parseAppFrame(frame: string): String {
        let frameData = new FrameData();
        if (frame == null) {
            frameData.code = resultCode.emptyError;
            frameData.data = "frame is mot allow empty";
            return JSON.stringify(frameData);
        }
        let apdu;
        let m698pdu = new M698pdu();
        // console.log(DataUtils.hexToBytes(frame))
        apdu = Apdu.getInstance().decode(DataUtils.hexToBytes(frame));
        let output = new ReverseByteArrayOutputStream();
        output.setBufSize(3000);
        apdu.getCosemPdu().encode(output);
        m698pdu.decode(new ReverseByteArrayInputStream(output.getArray()));
        return this.parseFrame(m698pdu);
    }

    parse(option: ParseOption) {
        let frame = option.frame;
        let frameData = new FrameData();
        if (frame == null || frame.length % 2 != 0) {
            frameData.code = resultCode.illegalError;
            frameData.data = "frame param is illegal or empty";
            option.result({
                msg: JSON.stringify(frameData)
            })
        }
        if (frame.startsWith("68") && frame.endsWith("16")) {
            option.result({
                msg: this.parseLinkFrame(frame)
            })
        } else {
            option.result({
                msg: this.parseAppFrame(frame.toString())
            })
        }
    }

    parseFrame(m698pdu: M698pdu): String {
        let result: String = "";
        switch (m698pdu.getChoiceIndex()) {
            case Choice.GET_RESPONSE:
                if (m698pdu.get_response.choice == 1) {
                    result = parseGetResponseNormal(m698pdu.get_response.getResponseNormal.result.result);
                } else if (m698pdu.get_response.choice == 2) {
                    result = parseGetResponseNormalList(m698pdu.get_response.getResponseNormalList.results);
                } else if (m698pdu.get_response.choice == 3) {
                    result = parseGetResponseRecord(m698pdu.get_response.getResponseRecord.results.respData);
                } else if (m698pdu.get_response.choice == 4) {
                    result = parseGetResponseRecordList(m698pdu.get_response.getResponseRecordList.results);
                } else if (m698pdu.get_response.choice == 5) {
                    result = parseGetResponseNext(m698pdu.get_response.getResponseNext.frameResp);
                }
                break;
            case Choice.SET_RESPONSE:
                if (m698pdu.set_response.choice == 1) {
                    result = parseSetNormalResponse(m698pdu.set_response.setResponseNormal);
                } else if (m698pdu.set_response.choice == 2) {
                    result = parseSetNormalResponseList(m698pdu.set_response.setResponseNormalList);
                } else if (m698pdu.set_response.choice == 3) {
                    result = parseSetThenGetResponse(m698pdu.set_response.setThenGetResponseNormalList);
                }
                break;
            case Choice.ACTION_RESPONSE:
                if (m698pdu.action_response.choice == 1) {
                    result = parseActionResponseNormal(m698pdu.action_response.actionResponseNormal);
                } else if (m698pdu.action_response.choice == 2) {
                    result = parseActionResponseNormalList(m698pdu.action_response.actionResponseNormalList)
                } else if (m698pdu.action_response.choice == 3) {
                    result = parseActionThenGetResponseList(m698pdu.action_response.actionThenGetResponseNormalList)
                }
                break;
            case Choice.CONNECT_RESPONSE:
                result = parseConnectResponse(m698pdu.connect_response.wConnObj);
                break;
            case Choice.SECURITY_RESPONSE:
                result = parseSecurityResponse(m698pdu.security_response);
                break;
            case Choice.PROXY_RESPONSE:
                if (m698pdu.proxy_response.choice == 1) {
                    result = parseProxyGetResponseList(m698pdu.proxy_response.proxyGetResponseList.result);
                } else if (m698pdu.proxy_response.choice == 2) {
                    result = parseProxyGetRecord(m698pdu.proxy_response.proxyGetResponseRecord);
                } else if (m698pdu.proxy_response.choice == 3) {
                    result = parseProxySetResponseNormalList(m698pdu.proxy_response.proxySetResponseList);
                } else if (m698pdu.proxy_response.choice == 4) {
                    result = parseProxySetThenGetResponseList(m698pdu.proxy_response.proxySetThenGetResponseList);
                } else if (m698pdu.proxy_response.choice == 5) {
                    result = parseProxyActionResponseList(m698pdu.proxy_response.proxyActionResponseList);
                } else if (m698pdu.proxy_response.choice == 6) {
                    result = parseProxyActionThenGetResponseList(m698pdu.proxy_response.proxyActionThenGetResponseList);
                } else if (m698pdu.proxy_response.choice == 7) {
                    result = parseProxyTransCommand(m698pdu.proxy_response.proxyTransCommandResponse);
                }
                break;
        }
        return result;
    }

}

